package net.minecraft.src;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;

public class TileSequenzer extends TileEntity
    implements IInventory
{
	private ItemStack sequencerVisibleContent[];
	private ItemStack sequencerContent[];
    private final int signalsInOneSequence = 3;
    
    private final int numberOfVisibleRows = 6;
    private final int numberOfRows = 18;
    private final int sequenceSize = numberOfRows * signalsInOneSequence;
    private final int visibleSequenceSize = numberOfVisibleRows * signalsInOneSequence;
    private final int timeSlots = 4; 
    private final int fullSize = sequenceSize + numberOfRows + timeSlots;
    
    private final int visibleSize =  visibleSequenceSize + numberOfVisibleRows + timeSlots;
    

    private final int sequnceIndexSlots = numberOfRows;
    
    private final int sequenceEnd = sequenceSize;
    private final int sequnceIndexEnd = sequenceEnd + sequnceIndexSlots;
    private final int timeEnd = sequnceIndexEnd + timeSlots;
    
    int scrolingStartRow;
    
    private int currentSequence = 0;
    private final int storagePacketEntitySize = 4;
    private ArrayList< boolean[] > sequence = new ArrayList< boolean[] >();
    public TileSequenzer()
    {
        sequencerContent = new ItemStack[fullSize];
        sequencerVisibleContent = new ItemStack[visibleSize];
        scrolingStartRow = 0;

    }

    public ItemStack getStackInSlotOnClosing(int par1)
    {
        if (sequencerContent[par1] != null)
        {
            ItemStack itemstack = sequencerContent[par1];
            sequencerContent[par1] = null;
            return itemstack;
        }
        else
        {
            return null;
        }
    }
    
    public int getSizeInventory()
    {
        return fullSize;
    }

    public  void  resetCounter()
    {
    	
    	currentSequence = 0;
    }
    
    public ItemStack getStackInSlot(int i)
    {
        return sequencerVisibleContent[i];
    }

    public ItemStack decrStackSize(int i, int j)
    {
        if (sequencerVisibleContent[i] != null)
        {
            if (sequencerVisibleContent[i].stackSize <= j)
            {
                ItemStack itemstack = sequencerVisibleContent[i];
                sequencerVisibleContent[i] = null;
                
                setItemStack(i, sequencerVisibleContent[i] );
                onInventoryChanged();
                return itemstack;
            }
            ItemStack itemstack1 = sequencerVisibleContent[i].splitStack(j);
            if (sequencerVisibleContent[i].stackSize == 0)
            {
            	sequencerVisibleContent[i] = null;
            }
            
            setItemStack(i, sequencerVisibleContent[i] );
            onInventoryChanged();
            return itemstack1;
        }
        else
        {
            return null;
        }
    }
    private  int getLimit()
    {
    	int i = 0;
    	
    	for( i=0 ; i < numberOfRows; ++i )
    	{
    		if(
	    		    sequencerContent[sequenceEnd + i] != null 
	    		&&  sequencerContent[sequenceEnd + i].itemID == Item.redstone.shiftedIndex
    		  )
    		  break; 
    		
    	}
    	return  i +1;
    	
    }
    
    private void updateSequenceArray()
    {
    	sequence.clear();
    	for( int i = 0; i < numberOfRows ; ++i )
    	{
    		boolean temp[] = new boolean [signalsInOneSequence];
    		for( int j = 0; j < signalsInOneSequence ; ++j )
    		{
    			temp[j]=false;
        		if(sequencerContent[j + i*signalsInOneSequence] == null)
        			continue;
        		if(sequencerContent[j + i*signalsInOneSequence].itemID == Item.redstone.shiftedIndex)
        		{
        			 temp[j]= true;
        		}	
    		}
    		sequence.add(temp);
    		
    	}
    }
    
    public  boolean [] getNextSequence()
    {
    	updateSequenceArray();
    	if(sequence.size() < 1 )
    		return null;
    	
    	if(
    			   getLimit() <= currentSequence
    			&& getLimit() != numberOfRows +1
    	  )
    		currentSequence = 0;
    	
    	if(sequence.listIterator(currentSequence).hasNext())
    		return sequence.listIterator(currentSequence++).next();
    	return null;
    }
    
    public int getTime()
    {
    	int time = 0;
    	for( int i = 0; i < timeSlots ; ++i )
    	{
    		if(sequencerContent[sequnceIndexEnd + i] == null)
    			continue;
    		if(sequencerContent[sequnceIndexEnd + i].itemID == Item.redstone.shiftedIndex)
    		{
    			time += 1 << i;
    		}
    	}
    	return time;
    }
    
    
    public void  inventoryScroled( int  currentFirstRow )
    {
    	scrolingStartRow = currentFirstRow;
    	updateAfterScroll();
	
    }
    
    private  void setItemStack(int position, ItemStack itemstack)
    {
    	if(setIntoSequence( position, itemstack ))
    		return;
    	
    	if(setIntoSequenceIndex( position, itemstack ))
    		return;
    	
    	if(setIntoTime( position, itemstack ))
    		return;
    	assert(false);
    }
    
    
    private void rewriteLoop ( ItemStack[] source, int size,ItemStack[] target, int start )
    {

    	for( int i = 0 ; i < size ; ++i  )
    	{
    		target[start+ i] = source[ i ];

    	}
    	
    	
    }
    
    private  void  updateAfterScroll()
    {
    	
    	rewriteLoop(
    			 getValidSequence()
    			,visibleSequenceSize
    			,sequencerVisibleContent
    			,0
    			);
        
    	rewriteLoop(
    		 getValidSequenceIndex()
   			,numberOfVisibleRows
   			,sequencerVisibleContent
   			,visibleSequenceSize
   			);
     
    	rewriteLoop(
    			 getValidTime()
      			,timeSlots
      			,sequencerVisibleContent
      			,visibleSequenceSize + numberOfVisibleRows
      			);
    	
    	
        if (ModLoader.getMinecraftInstance().theWorld.isRemote)
        {
        	Packet230ModLoader  packet = new Packet230ModLoader ();
        	saveSlider(packet);

            ModLoaderMp.sendPacket( ModLoaderMp.getModInstance(mod_AsPj.class), packet);
        }
        onInventoryChanged();

    }
    
    
    private boolean  setIntoSequence( int position, ItemStack itemstack )
    {
    	
    	int  potentialPosition = scrolingStartRow * signalsInOneSequence + position; 
    	if(position >= visibleSequenceSize)
    		return false;
    	
    	sequencerContent[potentialPosition] = itemstack;
    	return true;
    }
    
    private boolean  setIntoSequenceIndex( int position, ItemStack itemstack )
    {

    	int  potentialPosition =  scrolingStartRow + position - visibleSequenceSize; 
    	if( position >= visibleSequenceSize +  numberOfVisibleRows )
    		return false;
    	
    	if(potentialPosition < 0)
    		return  false;
    	
    	sequencerContent[potentialPosition+ sequenceEnd] = itemstack;
    	return true;
    }   
    
    private boolean  setIntoTime( int position, ItemStack itemstack )
    {
    	
    	int  potentialPosition = position- visibleSequenceSize-   numberOfVisibleRows ; 
    	if(position >= timeSlots + visibleSequenceSize +  numberOfVisibleRows  )
    		return false;
    	
    	if(potentialPosition < 0)
    		return  false;
    	
    	sequencerContent[sequnceIndexEnd + potentialPosition] = itemstack;
    	return true;
    }
    
    private  ItemStack[] getValidSequence()
    {
    	ItemStack[] sequence = new ItemStack[ visibleSequenceSize ];
    	
    	int offset = scrolingStartRow * signalsInOneSequence;
    	for(  int i = 0;i < visibleSequenceSize  ;++i)
    	{
    		sequence[ i ] = sequencerContent[offset + i];
    		
    	}
    	return sequence;
    }
 
    private  ItemStack[]  getValidSequenceIndex()
    {
    	ItemStack[] indexes = new ItemStack[ numberOfVisibleRows ];
    	int offset =  sequenceEnd+scrolingStartRow;
    	for(  int i = 0;i < numberOfVisibleRows  ;++i)
    	{
    		indexes[ i ] = sequencerContent[offset +i];
    		
    	}
    	return indexes;
    }    
    
    private ItemStack[]  getValidTime()
    {
    	ItemStack[]  times = new ItemStack[ timeSlots ];
    	
    	int offset = sequnceIndexEnd;
    	for(  int i = 0;i < timeSlots  ;++i)
    	{
    		times[ i ] = sequencerContent[offset + i];
    		
    	}
    	return times;
    }     
    
    public void setInventorySlotContents(int i, ItemStack itemstack)
    {
    	setItemStack(i, itemstack);
    	sequencerVisibleContent[i] = itemstack;
        if (itemstack != null && itemstack.stackSize > getInventoryStackLimit())
        {
            itemstack.stackSize = getInventoryStackLimit();
        }
        onInventoryChanged();
    }

    public String getInvName()
    {
        return "Sequenzer";
    }

    public void readFromNBT(NBTTagCompound nbttagcompound)
    {
        super.readFromNBT(nbttagcompound);
        NBTTagList nbttaglist = nbttagcompound.getTagList("Items");
        sequencerContent = new ItemStack[getSizeInventory()];
        for (int i = 0; i < nbttaglist.tagCount(); i++)
        {
            NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.tagAt(i);
            int j = nbttagcompound1.getByte("Slot") & 0xff;
            if (j >= 0 && j < sequencerContent.length)
            {
                sequencerContent[j] = ItemStack.loadItemStackFromNBT(nbttagcompound1);
            }
        }
        currentSequence = (int)nbttagcompound.getShort("CurrentSequence");
    }

    public void writeToNBT(NBTTagCompound nbttagcompound)
    {
        super.writeToNBT(nbttagcompound);
        NBTTagList nbttaglist = new NBTTagList();
        for (int i = 0; i < sequencerContent.length; i++)
        {
            if (sequencerContent[i] != null)
            {
                NBTTagCompound nbttagcompound1 = new NBTTagCompound();
                nbttagcompound1.setByte("Slot", (byte)i);
                sequencerContent[i].writeToNBT(nbttagcompound1);
                nbttaglist.appendTag(nbttagcompound1);
            }
        }
        
        nbttagcompound.setTag("Items", nbttaglist);
        nbttagcompound.setShort("CurrentSequence", (short)currentSequence);
    }
    
    public static  int[] concat(int[] first, int[] second) 
    {
    	  int[] result = Arrays.copyOf(first, first.length + second.length);
    	  System.arraycopy(second, 0, result, first.length, second.length);
    	  return result;
    }
    
    private void addItemStackTopacket( ItemStack  stack, int idNumber,Packet230ModLoader packet )
    {
    		if( stack == null )
    			return;
	    	int  itemArray[] = new int [storagePacketEntitySize];
	    	itemArray[0] = idNumber;
	    	itemArray[1] = stack.itemID;
	    	itemArray[2] = stack.stackSize;
	    	itemArray[3] = stack.getItemDamage();
	    	packet.dataInt = concat(packet.dataInt, itemArray);
    }


    public void loadFromPacket( Packet230ModLoader packet )
    {
    
        int  contentAreaLength = packet.dataInt.length - 3;

        
        if ( contentAreaLength  <= 0 )
        	return;
        assert( contentAreaLength % storagePacketEntitySize  == 0 );
        int  ptr  = 3;
        for ( int i =  0; i < sequencerContent.length; i ++)
        {
        	if( ptr >=  packet.dataInt.length )
        	{
        		sequencerContent[i]= null;
        		continue;
        	}	
        	if( 
        			   packet.dataInt[ptr+ 0] == i  
        			|| packet.dataInt.length  <= ptr
        	  )
        	{
        		sequencerContent[i]= null;
        		continue;
        	}
        	
			ItemStack  itemStack  =  new  ItemStack(packet.dataInt[ptr+ 1],packet.dataInt[ptr+ 2],packet.dataInt[ptr+ 3]);

			
			sequencerContent[i] = itemStack;
			ptr+=storagePacketEntitySize;
		}
    }

    public void saveSlider( Packet230ModLoader packet )
    {   
    	packet.packetType = mod_AsPj.idSequencerSliderPacket;
    	int [] integers =  new int [4];
    	integers[0] = xCoord;
		integers[1] = yCoord;
		integers[2] = zCoord;
    	integers[3] = scrolingStartRow;
    	packet.dataInt = integers;
    }
    
    public void saveIntoPacket( Packet230ModLoader packet )
    {   
    	
		packet.packetType = mod_AsPj.idSequencerPacket;
		int [] coords =  new int [3];
		
		coords[0] = xCoord;
		coords[1] = yCoord;
		coords[2] = zCoord;
		packet.dataInt = coords;
		for(int i = 0; i < sequencerContent.length; i++)
		{		
			addItemStackTopacket( sequencerContent[i],i,packet );
		}
    }


    public int getInventoryStackLimit()
    {
        return 1;
    }
    
    
    
    public boolean isUseableByPlayer(EntityPlayer entityplayer)
    {
        if (worldObj.getBlockTileEntity(xCoord, yCoord, zCoord) != this)
        {
            return false;
        }
        return entityplayer.getDistanceSq((double)xCoord + 0.5D, (double)yCoord + 0.5D, (double)zCoord + 0.5D) <= 64D;
    }
    
    public void openChest()
    {
    }

    public void closeChest()
    {
    }
}
